/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import Log from '../utils/log';

var cookie_str_splitter = /[:](?=\s*[a-zA-Z0-9_\-]+\s*[=])/g;

function CookieAccessInfo(domain, path, secure, script) {
    if (this instanceof CookieAccessInfo) {
        this.domain = domain || undefined;
        this.path = path || "/";
        this.secure = !!secure;
        this.script = !!script;
        return this;
    }
    return new CookieAccessInfo(domain, path, secure, script);
}

function Cookie(cookiestr, request_domain, request_path) {
    if (cookiestr instanceof Cookie) {
        return cookiestr;
    }
    if (this instanceof Cookie) {
        this.name = null;
        this.value = null;
        this.expiration_date = Infinity;
        this.path = String(request_path || "/");
        this.explicit_path = false;
        this.domain = request_domain || null;
        this.explicit_domain = false;
        this.secure = false; //how to define default?
        this.noscript = false; //httponly
        if (cookiestr) {
            this.parse(cookiestr, request_domain, request_path);
        }
        return this;
    }
    return new Cookie(cookiestr, request_domain, request_path);
}
Cookie.prototype.toString = function toString() {
    var str = [this.name + "=" + this.value];
    if (this.expiration_date !== Infinity) {
        str.push("expires=" + (new Date(this.expiration_date)).toUTCString());
    }
    if (this.domain) {
        str.push("domain=" + this.domain);
    }
    if (this.path) {
        str.push("path=" + this.path);
    }
    if (this.secure) {
        str.push("secure");
    }
    if (this.noscript) {
        str.push("httponly");
    }
    return str.join("; ");
};
Cookie.prototype.toValueString = function toValueString() {
    return this.name + "=" + this.value;
};

Cookie.prototype.parse = function parse(str, request_domain, request_path) {
    if (this instanceof Cookie) {
        var parts = str.split(";").filter(function(value) {
            return !!value;
        });
        var i;

        var pair = parts[0].match(/([^=]+)=([\s\S]*)/);
        if (!pair) {
            Log.showInfo("Invalid cookie header encountered. Header: '" + str + "'");
            return;
        }

        var key = pair[1];
        var value = pair[2];
        if (typeof key !== 'string' || key.length === 0 || typeof value !== 'string') {
            Log.showInfo("Unable to extract values from cookie header. Cookie: '" + str + "'");
            return;
        }

        this.name = key;
        this.value = value;

        for (i = 1; i < parts.length; i += 1) {
            pair = parts[i].match(/([^=]+)(?:=([\s\S]*))?/);
            key = pair[1].trim().toLowerCase();
            value = pair[2];
            switch (key) {
                case "httponly":
                    this.noscript = true;
                    break;
                case "expires":
                    this.expiration_date = value ?
                    Number(Date.parse(value)) :
                        Infinity;
                    break;
                case "path":
                    this.path = value ?
                    value.trim() :
                        "";
                    this.explicit_path = true;
                    break;
                case "domain":
                    this.domain = value ?
                    value.trim() :
                        "";
                    this.explicit_domain = !!this.domain;
                    break;
                case "secure":
                    this.secure = true;
                    break;
            }
        }

        if (!this.explicit_path) {
            this.path = request_path || "/";
        }
        if (!this.explicit_domain) {
            this.domain = request_domain;
        }

        return this;
    }
    return new Cookie().parse(str, request_domain, request_path);
};
Cookie.prototype.matches = function matches(access_info) {
    if (access_info === CookieAccessInfo.All) {
        return true;
    }
    if (this.noscript && access_info.script ||
    this.secure && !access_info.secure ||
    !this.collidesWith(access_info)) {
        return false;
    }
    return true;
};
Cookie.prototype.collidesWith = function collidesWith(access_info) {
    if ((this.path && !access_info.path) || (this.domain && !access_info.domain)) {
        return false;
    }
    if (this.path && access_info.path.indexOf(this.path) !== 0) {
        return false;
    }
    if (this.explicit_path && access_info.path.indexOf(this.path) !== 0) {
        return false;
    }
    var access_domain = access_info.domain && access_info.domain.replace(/^[\.]/, '');
    var cookie_domain = this.domain && this.domain.replace(/^[\.]/, '');
    if (cookie_domain === access_domain) {
        return true;
    }
    if (cookie_domain) {
        if (!this.explicit_domain) {
            return false; // we already checked if the domains were exactly the same
        }
        var wildcard = access_domain.indexOf(cookie_domain);
        if (wildcard === -1 || wildcard !== access_domain.length - cookie_domain.length) {
            return false;
        }
        return true;
    }
    return true;
};
export default Cookie;